/**
 * @constructor
 */
function BestEffortKeyboardListener(gameLoop, canvasId) {
	
	var self = this;
	$(document).bind("keydown", function(e){ self.onKeyDown(e); } );
	$(document).bind("keyup", function(e){ self.onKeyUp(e); } );
	this.gameLoop = gameLoop;
	
	this.pressedKeys = {};
	var qklSelf = this;
	
	this.onKeyDown = function(e) {
		if(qklSelf.pressedKeys[e.keyCode.toString()] == true) {
			return;
		}
		qklSelf.pressedKeys[e.keyCode.toString()] = true;
		
		var inputEventType = KEY_BINDINGS[e.keyCode];
		if(inputEventType != undefined && inputEventType != INPUT_EVENT_TYPE.kick &&  inputEventType != INPUT_EVENT_TYPE.punch) {
			var timeStamp = new Date().getTime();
			this.gameLoop.inputEvent = new InputEvent(inputEventType, INPUT_EVENT_STATE.start, timeStamp);
		}
	};
	
	this.onKeyUp = function(e) {
		delete qklSelf.pressedKeys[e.keyCode.toString()];
		
		var inputEventType = KEY_BINDINGS[e.keyCode];
		if(inputEventType != undefined) {
			var timeStamp = new Date().getTime();
			this.gameLoop.inputEvent = new InputEvent(inputEventType, INPUT_EVENT_STATE.end, timeStamp);
		}
	};
}

/**
 * @constructor
 * @param(Queue) inputQueue
 */
function QueuedKeyboardListener(inputQueue, canvasId) {
	
	var self = this;
	$(document).bind("keydown", function(e){ self.onKeyDown(e); } );
	$(document).bind("keyup", function(e){ self.onKeyUp(e); } );
	this.inputQueue = inputQueue;
	
	this.pressedKeys = {};
	var qklSelf = this;
	
	this.onKeyDown = function(e) {
		if(qklSelf.pressedKeys[e.keyCode.toString()] == true) {
			return;
		}
		qklSelf.pressedKeys[e.keyCode.toString()] = true;
		
		var inputEventType = KEY_BINDINGS[e.keyCode];
		if(inputEventType != undefined && inputEventType != INPUT_EVENT_TYPE.kick &&  inputEventType != INPUT_EVENT_TYPE.punch) {
			var timeStamp = new Date().getTime();
			this.inputQueue.push(new InputEvent(inputEventType, INPUT_EVENT_STATE.start, timeStamp));
		}
	};
	
	this.onKeyUp = function(e) {
		delete qklSelf.pressedKeys[e.keyCode.toString()];
		
		var inputEventType = KEY_BINDINGS[e.keyCode];
		if(inputEventType != undefined) {
			var timeStamp = new Date().getTime();
			this.inputQueue.push(new InputEvent(inputEventType, INPUT_EVENT_STATE.end, timeStamp));
		}
	};
}

/**
 * @Constructor
 */
function InputEvent(inputEventType, inputEventState, timeStamp) {
	this.type = inputEventType;
	this.state = inputEventState;
	this.timeStamp = timeStamp;
}

/**
 * @constructor
 * @param capacity
 * @returns {Queue}
 */
function Queue(capacity) {
	
	this.capacity = capacity;
	this.container = [];
	this.size = 0;
	
	/**
	 * @public
	 * @param element
	 */
	this.push = function(element) {
		if(this.isFull()) {
			return false;
		}
		this.container.push(element);
		this.size++;
		return true;
	};
	
	/**
	 * @public
	 */
	this.pop = function() {
		if(this.isEmpty()) {
			return null;
		}
		var element = this.container.shift();
		this.size--;
		return element;
	};
	
	/**
	 * @public
	 * @returns {Boolean}
	 */
	this.isEmpty = function() {
		return this.size==0;
	};
	
	/**
	 * @public
	 * @returns {Boolean}
	 */
	this.isFull = function() {
		return this.size==this.capacity;
	};
	
	this.debugToConsole = function() {
		var output = "";
		for(var i = 0; i<this.container.length; i++) {
			var inputEvent = this.container[i];
			if(inputEvent) {
				output += i+":["+ inputEvent.type+" "+inputEvent.state+"]";
			} else {
				output += i+":["+ nothing +"]";
			}			
		}
		if(output != "") {
			DEBUG_CONSOLE.toConsole(output);
		}		
		
	};
}